package com.bill99.rpc.service;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;

import com.bill99.rpc.RpcException;
import com.bill99.rpc.application.ApplicationBean;
import com.bill99.rpc.common.Constants;
import com.bill99.rpc.config.ServiceConfig;
import com.bill99.rpc.container.ServerInfo;
import com.bill99.rpc.protocol.hessian.HessianProtocolBean;
import com.bill99.rpc.registry.Registry;
import com.bill99.rpc.registry.RegistryBean;
import com.bill99.rpc.registry.url.RegistryUrl;
import com.bill99.rpc.registry.url.ServiceUrl;
import com.bill99.rpc.registry.zookeeper.ZookeeperRegistryFactory;
import com.bill99.rpc.registry.zookeeper.client.zkclient.ZkclientZookeeperTransporter;

/**
 * @author sheng.zhang
 * 
 */
public abstract class ServiceSupport extends ServiceConfig implements
		BeanClassLoaderAware, InitializingBean, ApplicationContextAware {

	private static final long serialVersionUID = 1L;
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	protected ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
	protected ApplicationContext applicationContext = null;

	public void setBeanClassLoader(ClassLoader classLoader) {
		this.beanClassLoader = classLoader;
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	protected ClassLoader overrideThreadContextClassLoader() {
		return ClassUtils.overrideThreadContextClassLoader(beanClassLoader);
	}

	protected void resetThreadContextClassLoader(ClassLoader original) {
		if (original != null) {
			Thread.currentThread().setContextClassLoader(original);
		}
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		//
		ServiceUrl serviceUrl = getServiceUrl();
		// 获取协议,并设置服务对象
		Map<?, ?> protocolBeans = applicationContext
				.getBeansOfType(HessianProtocolBean.class);
		if (!protocolBeans.isEmpty()) {
			for (Entry<?, ?> protocolBeanEntry : protocolBeans.entrySet()) {
				HessianProtocolBean bean = (HessianProtocolBean) protocolBeanEntry
						.getValue();
				if (this.protocol != null) {
					String[] protocols = protocol.split(",");
					for (String pname : protocols) {
						if (pname.equals(bean.getName())) {
							prepare(bean);
							serviceUrl = setPath(serviceUrl, bean.getPath());
						}
					}
				} else {
					prepare(bean);
					serviceUrl = setPath(serviceUrl, bean.getPath());
				}
			}
		}
		// 连接注册中心，进行服务注册
		Map<?, ?> registryBeans = applicationContext
				.getBeansOfType(RegistryBean.class);
		if (registryBeans.size() != 1)
			throw new RpcException(RpcException.UNKNOWN_EXCEPTION,
					"please check registry configuration,only one registry");
		Entry<?, ?> registryEntry = registryBeans.entrySet().iterator().next();
		RegistryBean registryBean = (RegistryBean) registryEntry.getValue();
		String addr = registryBean.getAddress();
		RegistryUrl registryUrl = new RegistryUrl(addr);
		ZookeeperRegistryFactory factory = new ZookeeperRegistryFactory();
		factory.setZookeeperTransporter(new ZkclientZookeeperTransporter());
		Registry registry = factory.getRegistry(registryUrl);
		// 设置应用参数信息
		Map<?, ?> applicationBeans = applicationContext
				.getBeansOfType(ApplicationBean.class);
		Entry<?, ?> applicationEntry = applicationBeans.entrySet().iterator()
				.next();
		ApplicationBean applicationBean = (ApplicationBean) applicationEntry
				.getValue();
		Map<String, String> serviceParameters = new HashMap<String, String>();
		serviceParameters.put(Constants.INTERFACE_KEY, this
				.getServiceInterface().getName());
		serviceParameters.put(Constants.APPLICATION_KEY,
				applicationBean.getName());
		serviceUrl = serviceUrl.addParameters(serviceParameters);
		//
		registry.register(serviceUrl);
	}

	private ServiceUrl setPath(ServiceUrl serviceUrl, String path) {
		return serviceUrl.setPath(path);
	}

	private void prepare(HessianProtocolBean bean) {
		prepareHessianProtocolBean(bean);
	}

	private void prepareHessianProtocolBean(HessianProtocolBean bean) {
		bean.setService(this.getService());
		bean.setServiceInterface(this.getServiceInterface());
		bean.prepare();
	}

	public ServiceUrl getServiceUrl() {
		ServerInfo serverInfo = ServerInfo.getServerInfo();
		return new ServiceUrl(Constants.HESSIAN_PROTOCOL, serverInfo.getIp(),
				serverInfo.getPort(), serverInfo.getPath());
	}

}
